package com.hhkj.study.admin.course.service.biz.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hhkj.study.admin.course.entity.Course;
import com.hhkj.study.admin.course.entity.CourseAssocResourceStat;
import com.hhkj.study.admin.course.model.podo.CourseDo;
import com.hhkj.study.admin.course.model.podo.CoursePo;
import com.hhkj.study.admin.course.model.req.CourseReq;
import com.hhkj.study.admin.course.model.res.CourseAssocResourceStatRes;
import com.hhkj.study.admin.course.model.res.CourseRes;
import com.hhkj.study.admin.course.service.base.CourseService;
import com.hhkj.study.admin.course.service.biz.CourseBizService;
import com.hhkj.study.admin.course.service.extend.CourseExtendService;
import com.hhkj.study.admin.dict.common.LevelCodeEnum;
import com.hhkj.study.admin.dict.entity.DictMultiLevel;
import com.hhkj.study.admin.dict.service.base.DictMultiLevelService;
import com.hhkj.study.admin.resource.entity.ResourceCourseBase;
import com.hhkj.study.admin.resource.factory.CourseResourceFactory;
import com.hhkj.study.admin.resource.service.extend.ResourceCourseBaseExtendService;
import com.hhkj.study.admin.teacher.entity.Teacher;
import com.hhkj.study.admin.teacher.service.base.TeacherService;
import com.hhkj.study.common.cache.GlobalCache;
import com.ruoyi.common.base.biz.service.biz.BaseBizServiceImpl;
import com.ruoyi.common.enums.DictCodeEnum;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
* CourseBizServiceImpl
*
* @author SERVER
* @since 2024-09-18
*/
@Service
public class CourseBizServiceImpl extends BaseBizServiceImpl<Course, CourseReq, CourseRes, CourseDo, CoursePo, CourseService, CourseExtendService> implements CourseBizService {

    @Resource
    private DictMultiLevelService dictMultiLevelService;

    @Resource
    private TeacherService teacherService;

    @Resource
    private GlobalCache globalCache;

    @Override
    protected void afterPage(List<CourseRes> courseResList) {
        super.afterPage(courseResList);

        Map<Long, String> dictMap = globalCache.cacheDictMap(Lists.newArrayList(DictCodeEnum.COURSE_TYPE.getCode()));
        for (CourseRes courseRes : courseResList){
            assignObject(courseRes, dictMap);
        }
    }

    @Override
    protected void afterGetById(CourseRes courseRes) {
        super.afterGetById(courseRes);

        Map<Long, String> dictMap = globalCache.cacheDictMap(Lists.newArrayList(DictCodeEnum.COURSE_TYPE.getCode()));
        assignObject(courseRes, dictMap);
        List<Long> teacherIdList = courseRes.getTeacherIdList();
        if (CollectionUtil.isNotEmpty(teacherIdList)) {
            List<Teacher> teacherList = teacherService.listByIds(teacherIdList);
            courseRes.setTeacherList(teacherList);
        }
    }

    private void assignObject(CourseRes courseRes, Map<Long, String> dictMap) {
        courseRes.setCategoryName(dictMap.get(courseRes.getCategoryId()));
        DictMultiLevel kind = dictMultiLevelService.getById(courseRes.getKindId());
        if (kind != null) {
            courseRes.setKindName(kind.getName());
        }
    }

    @Override
    protected void beforePage(CourseReq courseReq) {
        assignCourseType(courseReq);
    }


    @Override
    protected void beforeList(CourseReq courseReq) {
        assignCourseType(courseReq);
    }

    @Override
    protected void afterUpdate(CourseReq courseReq) {
        // 当更新课程表时会统计课程关联的资源情况
        if (CollectionUtil.isNotEmpty(courseReq.getStructureJson())) {
            // 异步统计课程关联的资源数据
            CompletableFuture.runAsync(() -> {
                this.extendService.saveStatCourseAssocResource(courseReq, null);
            });
        }
    }

    @Override
    protected void afterList(List<CourseRes> courseResList) {
        Map<Long, String> dictMap = globalCache.cacheDictMap(Lists.newArrayList(DictCodeEnum.COURSE_TYPE.getCode()));
        for (CourseRes courseRes : courseResList){
            assignObject(courseRes, dictMap);
        }
    }

    @Override
    public List<CourseAssocResourceStatRes> getCourseAssocResourceStatList(Collection<? extends Serializable> courseIdList) {
        if (CollectionUtil.isEmpty(courseIdList)) {
            return Lists.newArrayList();
        }
        List<Course> courseList = this.getExtendService().listByIdList(courseIdList);
        if (CollectionUtil.isEmpty(courseList)) {
            return Lists.newArrayList();
        }
        // 课程下所有资源
        List<CourseAssocResourceStat> courseAssocResourceTypeStatList = courseList.stream()
                .filter(e -> ObjectUtil.isNotNull(e.getAssocResourceStat()) && CollectionUtil.isNotEmpty(e.getAssocResourceStat().getCourseAssocResourceList()))
                .flatMap(userCourse -> userCourse.getAssocResourceStat().getCourseAssocResourceList().stream())
                .collect(Collectors.toList());
        if (CollectionUtil.isEmpty(courseAssocResourceTypeStatList)) {
            return Lists.newArrayList();
        }

        // 按resourceType分组
        Map<String, List<? extends ResourceCourseBase>> courseResourceTypeListMap = getResourceGroupTypeMap(courseAssocResourceTypeStatList);


        // 通过courseId resourceType分别分组
        Map<Long, Map<String, List<CourseAssocResourceStat>>> courseAssocResourceGroupListMap = courseAssocResourceTypeStatList.stream()
                .collect(Collectors.groupingBy(
                        CourseAssocResourceStat::getCourseId,
                        Collectors.groupingBy(CourseAssocResourceStat::getResourceType)
                ));
        // 最终返回课程关联资源列表 关联的视频 题库
        List<CourseAssocResourceStatRes> courseAssocResourceStatList = Lists.newArrayList();
        courseAssocResourceGroupListMap.forEach((courseId, courseAssocResourceMap) -> {
            CourseAssocResourceStatRes courseAssocResourceStatRes = new CourseAssocResourceStatRes();
            courseAssocResourceStatRes.setCourseId(courseId);
            courseAssocResourceStatRes.setResourceListByTypeMap(getResourceListByTypeMap(courseResourceTypeListMap, courseAssocResourceMap));
            courseAssocResourceStatList.add(courseAssocResourceStatRes);
        });
        return courseAssocResourceStatList;
    }

    /**
     * 根据资源类型和资源ID列表获取资源分组映射
     * 此方法首先根据资源类型对资源统计信息进行分组，然后将每个资源类型对应的资源ID列表转换为资源对象列表
     *
     * @param courseAssocResourceTypeStatList 课程关联资源统计信息列表，包含资源类型和资源ID列表等信息
     * @return 返回一个映射，其中键是资源类型，值是该资源类型对应的资源对象列表
     */
    public static Map<String, List<? extends ResourceCourseBase>> getResourceGroupTypeMap(List<CourseAssocResourceStat> courseAssocResourceTypeStatList) {
        if (CollectionUtil.isEmpty(courseAssocResourceTypeStatList)) {
            return Maps.newHashMap();
        }
        Map<String, Set<Long>> courseResourceTypeGroupMap = courseAssocResourceTypeStatList.stream()
                .collect(Collectors.groupingBy(
                        CourseAssocResourceStat::getResourceType,
                        Collectors.mapping(
                                CourseAssocResourceStat::getResourceIdList,
                                Collectors.toSet()
                        )
                ))
                .entrySet()
                .stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().stream()
                                .flatMap(List::stream)
                                .collect(Collectors.toSet())
                ));

        // 不同资源类型-具体资源列表
        Map<String, List<? extends ResourceCourseBase>> courseResourceTypeListMap = Maps.newHashMap();
        courseResourceTypeGroupMap.forEach((resourceType, resourceIdList) -> {
            ResourceCourseBaseExtendService resourceExtendService = CourseResourceFactory.getResourceServiceByType(resourceType);
            if (ObjectUtil.isNull(resourceExtendService)) {
                return;
            }
            List<? extends ResourceCourseBase> resourceList = resourceExtendService.listByIdList(resourceIdList);
            courseResourceTypeListMap.put(resourceType, resourceList);
        });
        return courseResourceTypeListMap;
    }

    /**
     * 根据资源类型获取资源列表的映射
     * 该方法的主要作用是通过关联资源映射和资源类型列表映射，筛选并收集特定类型的资源列表
     *
     * @param courseResourceTypeListMap 按资源类型分类的课程资源列表映射
     * @param courseAssocResourceMap 课程关联资源映射，包含各种资源及其统计信息
     * @return 返回一个映射，其中包含根据资源类型筛选出的资源列表
     */
    private static Map<String, List<? extends ResourceCourseBase>> getResourceListByTypeMap(Map<String, List<? extends ResourceCourseBase>> courseResourceTypeListMap,
                                                                                            Map<String, List<CourseAssocResourceStat>> courseAssocResourceMap) {
        if (CollectionUtil.isEmpty(courseAssocResourceMap)) {
            return Maps.newHashMap();
        }
        Map<String , List<? extends ResourceCourseBase>> resourceCourseMap = Maps.newHashMap();
        courseAssocResourceMap.forEach((resourceType, statList) -> {
            Set<Long> resourceIdSet = statList.stream().filter(e -> CollectionUtil.isNotEmpty(e.getResourceIdList()))
                    .flatMap(e -> e.getResourceIdList().stream())
                    .collect(Collectors.toSet());
            List<? extends ResourceCourseBase> resourceCourseList = courseResourceTypeListMap.get(resourceType);
            ResourceCourseBaseExtendService resourceExtendService = CourseResourceFactory.getResourceServiceByType(resourceType);
            if (ObjectUtil.isNull(resourceExtendService)) {
                return;
            }
            List<? extends ResourceCourseBase> resouceListByIdList = resourceExtendService.getResouceListByIdList(resourceIdSet, resourceCourseList);
            if (CollectionUtil.isNotEmpty(resouceListByIdList)) {
                resourceCourseMap.put(resourceType, resouceListByIdList);
            }
        });
        return resourceCourseMap;
    }

    private void assignCourseType(CourseReq courseReq) {
        if (ObjectUtil.isNotNull(courseReq.getCategoryParentId())) {
            LambdaQueryWrapper<DictMultiLevel> dictMultiLevelLambdaQuery = new LambdaQueryWrapper<>();
            dictMultiLevelLambdaQuery.eq(DictMultiLevel::getParentId, courseReq.getCategoryParentId()).eq(DictMultiLevel::getLevelCode, LevelCodeEnum.THIRD.getCode());
            List<DictMultiLevel> dictMultiLevelList = dictMultiLevelService.list(dictMultiLevelLambdaQuery);
            if (CollectionUtil.isNotEmpty(dictMultiLevelList)) {
                List<Long> dictIdList = dictMultiLevelList.stream().map(DictMultiLevel::getId).collect(Collectors.toList());
                courseReq.setCategoryIdList(dictIdList);
            }
        }
    }

}